/*
 * jlb
 */
package com.jlb.basic.service;

import com.alibaba.fastjson.JSON;
import com.baidu.fsg.uid.UidGenerator;
import com.google.common.collect.Maps;
import com.jlb.basic.dao.BasicAreaDAO;
import com.jlb.basic.entity.BasicArea;
import com.jlb.basic.vo.BasicAreaVO;
import com.jlb.core.base.BaseDAO;
import com.jlb.core.base.BaseSVImpl;
import com.jlb.core.common.Constants;
import com.jlb.core.exceptions.BaseException;
import com.jlb.core.exceptions.BasicAreaException;
import com.jlb.core.tools.StringTools;
import com.jlb.core.tools.redis.RedisKey;
import com.jlb.core.tools.redis.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service("basicAreaSV")
@Slf4j
public class BasicAreaSVImpl extends BaseSVImpl<BasicArea, Long> implements BasicAreaSV {
    private final static Logger logger = LoggerFactory.getLogger(BasicAreaSVImpl.class);

    @Autowired
    private BasicAreaDAO basicAreaDAO;

    @Resource
    private UidGenerator uidGenerator;

    @Resource
    private RedisUtils redisUtils;

    @Override
    protected BaseDAO getBaseDAO() {
        return basicAreaDAO;
    }


    /**
     * 根据areaCode获得单个区域对象
     *
     * @param areaCode 行政区域代码
     * @return BasicArea
     */
    @Override
    public BasicArea load(String areaCode) {

        if (StringUtils.isBlank(areaCode)) {
            logger.error("根据areaCode获得区域对象失败，原因：" + BaseException.BaseExceptionEnum.Ilegal_Param.toString() + ",areaCode:" + areaCode);
            throw new BasicAreaException(BaseException.BaseExceptionEnum.Ilegal_Param, areaCode);
        }

        BasicArea basicArea = null;
        String areaCacheKey = RedisKey.genAreaKey(areaCode);
        //判断 区域 是否缓存到redis
        if (!redisUtils.hasKey(areaCacheKey)) { //没缓存
            //先从库中查
            basicArea = basicAreaDAO.loadAreaCode(areaCode);
            if (basicArea == null)
                throw new BasicAreaException(BaseException.BaseExceptionEnum.Result_Not_Exist, areaCode);
            //放至缓存
            redisUtils.set(areaCacheKey, basicArea);
        } else {    // 已经缓存
            //直接读取缓存
            Object obj = redisUtils.get(areaCacheKey);
            if (obj == null) throw new BasicAreaException(BaseException.BaseExceptionEnum.Result_Not_Exist, areaCode);
            basicArea = (BasicArea) obj;
        }
        return basicArea;
    }

    /**
     * 获取所有省份
     *
     * @return List<BasicArea>
     */
    @Override
    public List<BasicArea> listProvoice() {
        String provoiceCacheKey = RedisKey.genAreaKey(Constants.PROVICES_DEFAULT_REDISKEY);
        List<BasicArea> provoices = null;
        if (!redisUtils.hasKey(provoiceCacheKey)) {
            provoices = basicAreaDAO.listProvoice();
            redisUtils.set(provoiceCacheKey, JSON.toJSONString(provoices));
        } else {
            String provoiceJson = redisUtils.get(provoiceCacheKey).toString();
            provoices = JSON.parseArray(provoiceJson, BasicArea.class);
        }
        return provoices;
    }

    /**
     * 获取所有指定省下级市
     *
     * @param area_code
     * @return
     */
    public List<BasicArea> listCitysByCode(String area_code) {
        String cacheKey = RedisKey.genAreaKey("citys:" + area_code);
        List<BasicArea> list = null;
        if (!redisUtils.hasKey(cacheKey)) {
            list = basicAreaDAO.listCitysByCode(area_code);
            redisUtils.set(cacheKey, JSON.toJSONString(list));
        } else {
            String areasJson = redisUtils.get(cacheKey).toString();
            list = JSON.parseArray(areasJson, BasicArea.class);
        }
        return list;
    }

    /**
     * 获取所有指定市下级县区
     *
     * @param area_code
     * @return
     */
    @Override
    public List<BasicArea> listCountysByCode(String area_code) {
        String cacheKey = RedisKey.genAreaKey("countys:" + area_code);
        List<BasicArea> list = null;
        if (!redisUtils.hasKey(cacheKey)) {
            list = basicAreaDAO.listCountyByCode(area_code);
            redisUtils.set(cacheKey, JSON.toJSONString(list));
        } else {
            String areasJson = redisUtils.get(cacheKey).toString();
            list = JSON.parseArray(areasJson, BasicArea.class);
        }
        return list;
    }

    /**
     * 获取所有指定县区下级乡镇
     *
     * @param area_code
     * @return
     */
    @Override
    public List<BasicArea> listTownsByCode(String area_code) {
        String cacheKey = RedisKey.genAreaKey("towns:" + area_code);
        List<BasicArea> list = null;
        if (!redisUtils.hasKey(cacheKey)) {
            list = basicAreaDAO.listTownsByCode(area_code);
            redisUtils.set(cacheKey, JSON.toJSONString(list));
        } else {
            String areasJson = redisUtils.get(cacheKey).toString();
            list = JSON.parseArray(areasJson, BasicArea.class);
        }
        return list;
    }

    /**
     * 加载所有区域对象至缓存
     *
     * @return
     */
    @Override
    public boolean queryAll2Redis() {
        List<BasicArea> list = basicAreaDAO.queryAll();
        Map<String, BasicArea> map = new HashMap<>();

        for (BasicArea basicArea : list) {
            map.put(basicArea.getAreaCode(), basicArea);
        }

        if (list != null && list.size() > 0) {
            redisUtils.set("area_cache", JSON.toJSONString(map));
            return true;
        }
        return false;
    }

    /**
     * 根据区域编码查询下级信息;
     *
     * @param area_code
     * @param level
     * @return
     */
    @Override
    public List<BasicArea> queryAreasByCode(String area_code, int level) {
        List<BasicArea> list = null;
        if (area_code == null || area_code.trim().equals("")) {
            //获取省份信息;
            list = this.listProvoice();
        } else {
            if (level == 2) {
                //获取市的信息
                list = this.listCitysByCode(area_code);
            } else if (level == 3) {
                //获取县的信息
                list = this.listCountysByCode(area_code);
            } else {
                //获取乡镇的信息;
                list = this.listTownsByCode(area_code);
            }
        }
        return list;
    }

    /**
     * 根据area_code 查询对象信息及下级区域信息;
     *
     * @param area_code
     * @return
     */
    @Override
    public Map<String, Object> getBasicAreaInfo(String area_code) {
        Map<String, Object> map = new HashedMap();
        List<BasicArea> basicAreaList = null;
        if (area_code != null && !area_code.equals("")) {
            BasicArea basicArea = basicAreaDAO.loadAreaCode(area_code);
            if (basicArea != null) {
                map.put("parentBasicArea", basicArea);//将对象放入map;
                int level = basicArea.getLevel();//获取对象等级;
                if (level == 1) {
                    //获取市的信息;
                    basicAreaList = this.listCitysByCode(area_code);
                } else if (level == 2) {
                    //获取县的信息;
                    basicAreaList = this.listCountysByCode(area_code);
                } else if (level == 3) {
                    //获取县的信息;
                    basicAreaList = this.listTownsByCode(area_code);
                }
                if (basicAreaList != null && basicAreaList.size() > 0) {
                    map.put("childBasicArea", basicAreaList);
                }
            }
        }
        return map;
    }

    /**
     * 根据区域编码获取区域信息;
     *
     * @param area_code
     * @return
     */
    @Override
    public List<BasicArea> getAreaByAreaCode(String area_code, String area_name) {
        BasicArea basicArea = null;
        Map<String, Object> map = new HashedMap();
        if (area_code != null && !area_code.equals("")) {
            map.put("areaCode", area_code);
        }
        if (area_name != null && !area_name.equals("")) {
            map.put("areaName", area_name);
        }
        List<BasicArea> basicAreaList = basicAreaDAO.loadByParam(map);
        return basicAreaList;
    }

    /**
     * 根据区域编号修改区域信息（只能修改地区名称）
     * <p>
     * 1.参数判断
     * 2.根据区域编码查询对象，获得该对象的level
     * 2.根据level对areaCode进行截取拼接,根据拼接后的编码查询上一级的区域名称
     * 3.拼接fullName
     * 4.数据封装
     * 5.修改区域信息
     * 暂不考虑层级关系，只改当前级数据
     *
     * @param areaCode 区域编码
     * @param areaName 区域名称
     */
    @Override
    public void updateNameByCode(String areaCode, String areaName) {

        if (!StringTools.isNotEmpty(areaCode))
            throw new BasicAreaException(BaseException.BaseExceptionEnum.Ilegal_Param, "区域编码");
        if (!StringTools.isNotEmpty(areaName))
            throw new BasicAreaException(BaseException.BaseExceptionEnum.Ilegal_Param, "区域名称");

        String fullName;
        //根据区域编码进行区域查询，并获取level,若区域对象数据为空,则给出提示信息
        BasicArea basicArea = basicAreaDAO.loadAreaCode(areaCode);

        //根据区域名称查询是否已存在同名的区域名称，若区域名称已存在，给出提示信息
        //Boolean flag = isExist("areaName", areaName);
        //if (flag) throw new BasicAreaException(BaseException.BaseExceptionEnum.Exists, "区域名称");
        //根据level截取获得上一级编码，并根据编码查询上一级区域名称
        //测试数据
        int level = basicArea.getLevel();
        String pAreaCode = null;
        //等级 省1 市2 县3 乡4 村5
        if (level == 1) {
            pAreaCode = areaCode;
        } else if (level == 2) {
            pAreaCode = areaCode.substring(0, 2);
        } else if (level == 3) {
            pAreaCode = areaCode.substring(0, 4);
        } else if (level == 4) {
            pAreaCode = areaCode.substring(0, 6);
        } else if (level == 5) {
            pAreaCode = areaCode.substring(0, 9);
        }

        BasicArea pBasicArea = basicAreaDAO.loadAreaCode(pAreaCode);

        if (level == 1) {
            fullName = areaName;
        } else {
            fullName = pBasicArea.getFullName() + areaName;
        }

        //数据封装
        Map<String, Object> map = Maps.newHashMap();
        map.put("areaCode", areaCode);
        map.put("areaName", areaName);
        map.put("fullName", fullName);

        //修改区域信息
        basicAreaDAO.updateNameByCode(map);

    }

    /**
     * 添加区域
     * <p>
     * 1.参数判断
     * 2.根据level和区域编码查询上级区域信息
     * 3.根据level和上级区域信息构造子级区域信息
     * 4.保存区域对象
     *
     * @param level    区域级别
     * @param areaCode 区域编码
     * @param areaName 区域名称
     */
    @Override
    public void addArea(Integer level, String areaCode, String areaName) {

        //参数判断
        if (level == null)
            throw new BasicAreaException(BaseException.BaseExceptionEnum.Ilegal_Param, "区域级别");
        if (!StringTools.isNotEmpty(areaCode))
            throw new BasicAreaException(BaseException.BaseExceptionEnum.Ilegal_Param, "区域编码");
        if (!StringTools.isNotEmpty(areaName))
            throw new BasicAreaException(BaseException.BaseExceptionEnum.Ilegal_Param, "区域名称");
        String pAreaCode;
        BasicArea basicArea = new BasicArea();
        //根据level和区域编码查询上级区域信息
        if (level == 1) {
            basicArea.setAreaCode(areaCode);
            basicArea.setAreaName(areaName);
            basicArea.setProvince(areaCode);
            basicArea.setCity(areaCode);
            basicArea.setCounty(areaCode);
            basicArea.setTown(areaCode);
            basicArea.setLevel(1);
        } else if (level == 2) {
            //根据level和上级区域信息构造子级区域信息
            basicArea.setAreaCode(areaCode);
            pAreaCode = areaCode.substring(0, 2);
            BasicArea basicArea2 = basicAreaDAO.loadAreaCode(addZeroForNum(pAreaCode, 12));
            basicArea.setProvince(basicArea2.getProvince());
            basicArea.setAreaName(areaName);
            basicArea.setFullName(basicArea2.getAreaName() + areaName);
            basicArea.setCity(areaCode);
            basicArea.setCounty(areaCode);
            basicArea.setTown(areaCode);
            basicArea.setLevel(2);
        } else if (level == 3) {
            basicArea.setAreaCode(areaCode);
            pAreaCode = areaCode.substring(0, 4);
            BasicArea basicArea3 = basicAreaDAO.loadAreaCode(addZeroForNum(pAreaCode, 12));
            basicArea.setProvince(basicArea3.getProvince());
            basicArea.setCity(basicArea3.getAreaCode());
            basicArea.setAreaName(areaName);
            basicArea.setFullName(basicArea3.getFullName() + areaName);
            basicArea.setCounty(areaCode);
            basicArea.setTown(areaCode);
            basicArea.setLevel(3);
        } else if (level == 4) {
            basicArea.setAreaCode(areaCode);
            pAreaCode = areaCode.substring(0, 6);
            BasicArea basicArea4 = basicAreaDAO.loadAreaCode(addZeroForNum(pAreaCode, 12));
            basicArea.setProvince(basicArea4.getProvince());
            basicArea.setCity(basicArea4.getCity());
            basicArea.setAreaName(areaName);
            basicArea.setFullName(basicArea4.getFullName() + areaName);
            basicArea.setCounty(basicArea4.getAreaCode());
            basicArea.setTown(areaCode);
            basicArea.setLevel(4);
        }
        //保存区域对象
        basicAreaDAO.addArea(basicArea);
    }

    /**
     * 根据code 和 区域名称判断是否存在;
     *
     * @param areaCode
     * @param areaName
     * @return
     */
    @Override
    public boolean isExistArea(String areaCode, String areaName, int level) {
        boolean flag = false;
        String area_code = null;
        Map<String, Object> map = new HashedMap();
        if (level == 1) {
            area_code = areaCode.substring(0, 2);
        } else if (level == 2) {
            area_code = areaCode.substring(0, 2);
        } else if (level == 3) {
            area_code = areaCode.substring(0, 4);
        } else {
            area_code = areaCode.substring(0, 6);
        }
        map.put("areaCode", area_code);
        map.put("areaName", areaName);
        List<BasicArea> basicArea = basicAreaDAO.isExistArea(map);
        if (!basicArea.isEmpty() && basicArea.size() > 0) {
            flag = true;
        }
        return flag;
    }

    /**
     * 查询指定级别之上的所有对象json串
     *
     * @param level 指定级别
     * @return
     */
    @Override
    public List<BasicAreaVO> queryAreasLevel(int level) {
        //查询出所有省区域
        List<BasicArea> list_1 = queryAreasByCode(null, 1);

        //如果不是1-4级，则返回空
        if (level < 1 || level > 4) return null;

        List<BasicAreaVO> vos_1 = new ArrayList<>();

        //遍历一级区域，把一级区域对象放至返回对象中
        list_1.forEach(area1 -> {
            BasicAreaVO vo1 = new BasicAreaVO();
            vo1.setBasicArea(area1);
            if (level >= 2) {
                //查询出一级区域下所有二级区域对象
                List<BasicArea> list_2 = this.queryAreasByCode(area1.getAreaCode(), 2);
                List<BasicAreaVO> vos_2 = new ArrayList<>();
                //遍历二级所有区域，准备查询下级区域
                list_2.forEach(area2 -> {
                    BasicAreaVO vo2 = new BasicAreaVO();
                    vo2.setBasicArea(area2);
                    if (level >= 3) {
                        //查询出二级区域下所有三级区域对象
                        List<BasicArea> list_3 = this.queryAreasByCode(area2.getAreaCode(), 3);
                        List<BasicAreaVO> vos_3 = new ArrayList<>();
                        list_3.forEach(area3 -> {
                            BasicAreaVO vo3 = new BasicAreaVO();
                            vo3.setBasicArea(area3);
                            if (level == 4) {
                                //查询出三级区域下所有四级区域对象
                                List<BasicArea> list_4 = this.queryAreasByCode(area3.getAreaCode(), 4);
                                List<BasicAreaVO> vos_4 = new ArrayList<>();
                                list_4.forEach(area4 -> {
                                    BasicAreaVO vo4 = new BasicAreaVO();
                                    vo4.setBasicArea(area4);
                                    vos_4.add(vo4);
                                });
                                vo3.setChildren(vos_4);
                            }
                            vos_3.add(vo3);
                        });
                        vo2.setChildren(vos_3);
                    }
                    vos_2.add(vo2);
                });
                vo1.setChildren(vos_2);
            }
            vos_1.add(vo1);
        });
        return vos_1;
    }

    /**
     * 补0
     *
     * @param str
     * @param strLength
     * @return
     */
    public static String addZeroForNum(String str, int strLength) {
        int strLen = str.length();
        StringBuffer sb = null;
        while (strLen < strLength) {
            sb = new StringBuffer();
            //sb.append("0").append(str);// 左补0
            sb.append(str).append("0");//右补0
            str = sb.toString();
            strLen = str.length();
        }
        return str;
    }

    /*
    华北（北京市、天津市、山西省、河北省、内蒙古自治区中部）；
    东北（黑龙江省、吉林省、辽宁省、内蒙古自治区东部）
    华东（上海市、江苏省、浙江省、安徽省、福建省、江西省、山东省、台湾省）；
    华中（河南省、湖北省、湖南省）；
    华南（广东省、广西壮族自治区、海南省、香港特别行政区、澳门特别行政区）；
    西南（四川省、贵州省、云南省、重庆市、西藏自治区）；
    西北（陕西省、甘肃省、青海省、宁夏回族自治区、新疆维吾尔自治区、内蒙古自治区西部）；
    --------------------------------------------------------------------------------------------------------------------
     11: "北京", 12: "天津", 13: "河北", 14: "山西", 15: "内蒙古", //华北两市三省
     21: "辽宁", 22: "吉林", 23: "黑龙江", //东北三省
     31: "上海", 32: "江苏", 33: "浙江", 34: "安徽", 35: "福建", 36: "江西", 37: "山东", //华东一市六省
     41: "河南", 42: "湖北", 43: "湖南", 44: "广东", 45: "广西", 46: "海南", //华南五省
     50: "重庆", 51: "四川", 52: "贵州", 53: "云南", 54: "西藏",//西南一市四省
     61: "陕西", 62: "甘肃", 63: "青海", 64: "宁夏", 65: "新疆",//西北五省
     71: "台湾",
     81: "香港", 82: "澳门",
     91: "国外";
    */
    /**
     * 生成中国大区及区内省份json串
     * @param args
     */
    /*public static void main(String[] args) {
        List<ChinaAreaDTO> china_area = new ArrayList<>();
        String strs = "110000000000,120000000000,130000000000,140000000000,150000000000";
        china_area.add(new ChinaAreaDTO("1", "华北", Arrays.asList(strs.split(","))));
        strs = "210000000000,220000000000,230000000000";
        china_area.add(new ChinaAreaDTO("2", "东北", Arrays.asList(strs.split(","))));
        strs = "310000000000,320000000000,330000000000,340000000000,350000000000,360000000000,370000000000";
        china_area.add(new ChinaAreaDTO("3", "华东", Arrays.asList(strs.split(","))));
        strs = "410000000000,420000000000,430000000000,440000000000,450000000000,460000000000";
        china_area.add(new ChinaAreaDTO("4", "华南", Arrays.asList(strs.split(","))));
        strs = "500000000000,510000000000,520000000000,530000000000,540000000000";
        china_area.add(new ChinaAreaDTO("5", "西南", Arrays.asList(strs.split(","))));
        strs = "610000000000,620000000000,630000000000,640000000000,650000000000";
        china_area.add(new ChinaAreaDTO("6", "西北", Arrays.asList(strs.split(","))));
//        china_area.add(new ChinaAreaDTO("7", "台湾", ""));
//        china_area.add(new ChinaAreaDTO("8", "港澳", ""));
//        china_area.add(new ChinaAreaDTO("9", "国外", ""));
        System.out.println("china_area = " + JSON.toJSONString(china_area));
    }*/


}
